package com.ydj.app.third.ai.deepseek;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.google.gson.Gson;
import com.ydj.app.third.ai.ChatFluxListener;
import com.ydj.framework.exception.CommonException;
import com.ydj.framework.utils.BooleanValue;
import com.ydj.framework.utils.JsonUtils;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.scheduler.Schedulers;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Component
public class DeepseekManager {
    @Value("${deepseek.apiKey}")
    private String apiKey;

    private final String baseUrl = "https://api.deepseek.com";

    public String chatFetchCode(String systemPrompt, String userPrompt, String modelCode, Double temperature, String languageDesc) throws CommonException {
        DeepseekChatCompletionsRes dsRes = chat(systemPrompt, userPrompt, modelCode, temperature, DeepseekResponseFormatEnum.Json);
        if (dsRes == null) {
            CommonException.throwException("出现错误，请再试一次");
        }
        if (dsRes.getError() != null) {
            DeepseekChatCompletionsRes.ErrorBean errorBean = dsRes.getError();
            String msg = String.format("出现错误。错误码：%s。原因：%s", errorBean.getCode(), errorBean.getMessage());
            CommonException.throwException(msg);
        }
        if (dsRes.getChoices().isEmpty()) {
            CommonException.throwException("出现错误，模型返回缺失，请再试一次");
        }
        DeepseekChatCompletionsRes.ChoicesBean choicesBean = dsRes.getChoices().get(0);
        String content = choicesBean.getMessage().getContent();

        // 裁剪出html代码。正则找到 【```html】到【```】的一段内容。 如果不能提取，就整段保存好了
        String regex = "```" + languageDesc + "(.*?)```";
        Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
            content = matcher.group(1).trim();
        }

        return content;
    }

    public DeepseekChatCompletionsRes chat(String systemPrompt, String userPrompt, String modelName, Double temperature, DeepseekResponseFormatEnum responseFormat) {
        String url = baseUrl + "/chat/completions";
        try {

            List<DeepseekChatCompletionsReq.MessagesBean> messagesBeanList = new ArrayList<>();
            messagesBeanList.add(new DeepseekChatCompletionsReq.MessagesBean()
                    .setRole("system")
                    .setContent(systemPrompt));
            messagesBeanList.add(new DeepseekChatCompletionsReq.MessagesBean()
                    .setRole("user")
                    .setContent(userPrompt));

            DeepseekChatCompletionsReq req = new DeepseekChatCompletionsReq()
                    .setMessages(messagesBeanList)
                    .setModel(modelName)
                    .setFrequency_penalty(0)
                    .setMax_tokens(8192)
                    .setPresence_penalty(0)
                    .setResponse_format(new DeepseekChatCompletionsReq.ResponseFormatBean().setType(responseFormat.getProtocolName()))
                    .setStream(false)
                    .setTemperature(temperature);

            String body = JsonUtils.toJson(req);

            long sendTs = System.currentTimeMillis();
            HttpResponse receiveRes = HttpRequest.post(url)
                    .header("Content-Type", "application/json")
                    .header("Accept", "application/json")
                    .header("Authorization", "Bearer " + apiKey)
                    .body(body)
                    .timeout(300 * 1000)
                    .setReadTimeout(0)
                    .execute();
            long costTime = System.currentTimeMillis() - sendTs;

            String receive = receiveRes.body();
            log.info("【DEEPSEEK发送对话】返回" + receive);

            DeepseekChatCompletionsRes res = new Gson().fromJson(receive, DeepseekChatCompletionsRes.class);
            if (res != null) {
                res.setCostTime(costTime);
            }
            return res;
        } catch (Exception e) {
            return null;
        }
    }

    public void chatFlux(String systemPrompt, String userPrompt, String modelName, Double temperature, DeepseekResponseFormatEnum responseFormat, ChatFluxListener listener) {
        //构建deepseek请求体
        List<DeepseekChatCompletionsReq.MessagesBean> messagesBeanList = new ArrayList<>();
        messagesBeanList.add(new DeepseekChatCompletionsReq.MessagesBean()
                .setRole("system")
                .setContent(systemPrompt));
        messagesBeanList.add(new DeepseekChatCompletionsReq.MessagesBean()
                .setRole("user")
                .setContent(userPrompt));
        DeepseekChatCompletionsReq req = new DeepseekChatCompletionsReq()
                .setMessages(messagesBeanList)
                .setModel(modelName)
                .setFrequency_penalty(0)
                .setMax_tokens(8192)
                .setPresence_penalty(0)
                .setResponse_format(new DeepseekChatCompletionsReq.ResponseFormatBean().setType(responseFormat.getProtocolName()))
                .setStream(true)
                .setTemperature(temperature);
        String body = JsonUtils.toJson(req);

        //创建webclient客户端
        WebClient webClient = WebClient.create(baseUrl);
        BooleanValue thinking = new BooleanValue(false);
        webClient.post()
                .uri("/chat/completions")
                .contentType(MediaType.APPLICATION_JSON)
                .header("Authorization", "Bearer " + apiKey)
                .bodyValue(body)
                .accept(MediaType.TEXT_EVENT_STREAM)
                .retrieve()
                .bodyToFlux(String.class)
                .subscribeOn(Schedulers.boundedElastic())
                .doOnError(e -> {
                    log.error("异常:", e);
                    listener.error(e);
                })
                .subscribe(re -> {
                    log.info("收到消息:{}", re);
                    if ("[DONE]".equals(re)) {
                        listener.flux(re, true);
                        return;
                    }
                    DeepseekChatStreamCompletionsRes deepseekChatStreamCompletionsRes = JsonUtils.jsonToBean(re, DeepseekChatStreamCompletionsRes.class);

                    DeepseekChatStreamCompletionsRes.ChoicesBean.DeltaBean deltaBean = Optional.ofNullable(deepseekChatStreamCompletionsRes)
                            .map(DeepseekChatStreamCompletionsRes::getChoices)
                            .map(choicesBeans -> choicesBeans.get(0))
                            .map(DeepseekChatStreamCompletionsRes.ChoicesBean::getDelta)
                            .orElse(null);
                    String content = "";
                    if (deltaBean != null) {
                        if (deltaBean.getReasoning_content() != null) {
                            if (!thinking.isValue()) {
                                thinking.setValue(true);
                                content += "<think>";
                            }
                            content += deltaBean.getReasoning_content();
                        }
                        if (deltaBean.getContent() != null) {
                            if (thinking.isValue()) {
                                thinking.setValue(false);
                                content += "</think>";
                            }
                            content += deltaBean.getContent();
                        }
                    }
                    listener.flux(content, false);

                });

    }

}
